package app

import (
	"d-serv-go/server/core/base"
	"d-serv-go/server/core/bean"
	"d-serv-go/server/core/handlers"
	"d-serv-go/server/core/local"
	"d-serv-go/server/core/log"
	"fmt"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/cache"
	"github.com/gofiber/fiber/v2/middleware/cors"
	"github.com/gofiber/fiber/v2/middleware/pprof"
	"github.com/gofiber/fiber/v2/middleware/recover"
	"github.com/gofiber/template/html"
	"github.com/gofiber/websocket/v2"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
)

func InitFiber() {
	engine := html.New("./templates", ".html")
	app := fiber.New(fiber.Config{
		Views: engine,
		// Override default error handler
		ErrorHandler: func(ctx *fiber.Ctx, err error) error {
			// Status code defaults to 500
			// code := fiber.StatusInternalServerError

			// Retrieve the custom status code if it's an fiber.*Error
			out := bean.NewOutBean()
			if e, ok := err.(*fiber.Error); ok {
				// code = e.Code
				out.SetError(e.Message.(string))
			}
			if e, ok := err.(*base.TipError); ok {
				// code = e.Code
				out.SetError(e.Message)
			} else {

				msg := fmt.Sprintf("内部错误:%v", err)
				log.Error(msg)
				out.SetError("内部错误")
			}
			local.RemoveAll()
			// ctx.JSON(out)
			json, _ := out.MarshalJSON()
			ctx.Send(json)

			// Return from handler
			return nil
		},
	})
	//
	app.Use(recover.New())
	//
	app.Use(pprof.New())
	// public目录里为静态资源
	app.Static("/", "./public", fiber.Static{
		Compress:      true,
		ByteRange:     true,
		Browse:        true,
		Index:         "john.html",
		CacheDuration: 10 * time.Second,
		MaxAge:        3600,
	})
	// TODO get var from config
	//app.Use(cors.New(cors.Config{
	//	AllowOrigins: "https://gofiber.io, https://gofiber.net",
	//	AllowHeaders: "Origin, Content-Type, Accept",
	//}))

	var ConfigDefault = cors.Config{
		Next:             nil,
		AllowOrigins:     "*",
		AllowMethods:     "GET,POST,HEAD,PUT,DELETE,PATCH",
		AllowHeaders:     "",
		AllowCredentials: false,
		ExposeHeaders:    "",
		MaxAge:           0,
	}
	app.Use(cors.New(ConfigDefault))

	//app.Use(cors.New(cors.Config{
	//	AllowOrigins: "https://gofiber.io, https://gofiber.net",
	//	AllowHeaders:  "Origin, Content-Type, Accept",
	//}))

	app.Get("/", func(c *fiber.Ctx) error {
		return c.SendString("Powered by d-serv-go")
	})
	app.Get("*.*.do", handlers.ServHandler)
	app.Post("*.*.do", handlers.ServHandler)
	app.Use(cache.New(cache.Config{
		Next: func(c *fiber.Ctx) bool {
			return strings.Contains(c.Route().Path, "/ws")
		},
	}))
	// websocket
	app.Use("/ws", func(c *fiber.Ctx) error {
		// IsWebSocketUpgrade returns true if the client
		// requested upgrade to the WebSocket protocol.
		if websocket.IsWebSocketUpgrade(c) {
			c.Locals("allowed", true)
			return c.Next()
		}
		return fiber.ErrUpgradeRequired
	})
	// websocket
	app.Get("/ws/:id", websocket.New(func(c *websocket.Conn) {
		// c.Locals is added to the *websocket.Conn
		log.Info(c.Locals("allowed"))  // true
		log.Info(c.Params("id"))       // 123
		log.Info(c.Query("v"))         // 1.0
		log.Info(c.Cookies("session")) // ""

		// websocket.Conn bindings https://pkg.go.dev/github.com/fasthttp/websocket?tab=doc#pkg-index
		var (
			mt  int
			msg []byte
			err error
		)
		for {
			if mt, msg, err = c.ReadMessage(); err != nil {
				log.Info("read:", err)
				break
			}
			log.Info("recv: %s", msg)

			if err = c.WriteMessage(mt, msg); err != nil {
				log.Info("write:", err)
				break
			}
		}

	}))

	err := app.Listen(":3000")
	if err != nil {
		log.Fatal(err)
	}
	notifySignal(app)
	log.Fatal("server exit")
}

func notifySignal(app *fiber.App) {
	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)

	go func() {
		s := <-c
		log.Infof("got signal [%s], exiting now", s)
		if err := app.Shutdown(); nil != err {
			log.Error("server close failed: " + err.Error())
		}

		log.Infof("Exited")
		os.Exit(0)
	}()
}
